/*=+--+=#=+--      UAS Severe Weather Simulation Softeware        --+=#=+--+=#*\
|          Copyright (C) 2013 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |
                                                                                
     This program is free software: you can redistribute it and/or modify       
     it under the terms of the GNU General Public License version 2 as          
     published by the Free Software Foundation.                                 
                                                                                
     This program is distributed in the hope that it will be useful,            
     but WITHOUT ANY WARRANTY; without even the implied warranty of             
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              
     GNU General Public License for more details.                               
                                                                                
     You should have received a copy of the GNU General Public License          
     along with this program.  If not, see <http://www.gnu.org/licenses/>.      
                                                                                
            Jack Elston                           Cory Dixon                    
|           elstonj@colorado.edu                  dixonc@colorado.edu          |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/
/***********************************************************************
 * FILENAME:
 * Thread.h
 *
 * PURPOSE:
 *   Implemnts a thread class object using pThreads.
 *
 * CREATED:
 * 11/2000 by Cory Dixon
 *
 * LAST MODIFIED:
 * $Author: dixonc $
 * $Date: 2005/11/02 20:27:20 $
 * $Revision: 1.4 $
 *
 ***********************************************************************/

#ifndef _PTHREAD_VC_H
#define _PTHREAD_VC_H

// standard headers
#include <pthread.h>
#include <signal.h>

// include project headers
#include "String.h"
#include "shmStruct.h"
#include "timeLib.h"

#define TSIGQUIT        SIGUSR1         // used to signal thread exit
#define TSIGTIMER       SIGALRM         // default thread interval timer

class pThread
{
	protected:
		//----------------------------------------------------------
		// Data members
		//----------------------------------------------------------
		ShmStruct         *shmPtr;	// pointer to global

		String             name;  // name of task
		pid_t              pid;   // process id to task
		pthread_t          tid;   // thread id to task
		pthread_mutex_t    p_mtx;	// mutex handle, use shared memory one if available
		pthread_attr_t     attr;
		struct sched_param param;

		bool         running;	// if loop is running
		float        runRate;	// actual run rate
		unsigned int runCount;	// number of runs	
		float        runTime;	// length of up time

		float 				timeStep;	// time step in microsecs
		TimeStamp 			currentStamp;	// time=t (now)	
		TimeStamp 			startStamp;	// start of thread
		TimeStamp			lastStamp;	// time=t-1 (last one)

		static unsigned int	threadNumber;	// static count of thread
		unsigned int			myNumber;	// my thread number 

		IntervalTimer 			*itPtr;

	public:
		volatile float			execRate;	// desired run rate

		//----------------------------------------------------------
		// friend Functions
		//----------------------------------------------------------
		// provides a function to spawn the run functions of the
		// tasks
		friend void *startFunc(void *task);

		// handle signals to threads.  Should only be
		// TSIGQUIT which is a local defined signal for
		// task to quit
		friend void sigHandler(int signo, siginfo_t *info, void *extra);

	public:
		//----------------------------------------------------------
		// member Functions
		//----------------------------------------------------------
		// constructor, takes a name for the name of the thread
		// which goes to base class
		pThread(String nameStr="pThread");
		//pThread();

		// Destructor  
		virtual ~pThread();

		// initialize thread, call before start
		virtual bool init( ShmStruct * shmStructPtr );

		// This is called to create and run a thread for the
		// thread class. This function should NOT be overloaded.
		// 	rate - set the execRate, ie try to run at this rate
		// 	prio - set the priority of the thread, -1 does not spawn
		//          the thread.  A prio=0 doesn't use scheduling 
		//          and prio>0 uses thread priority
		int start(float rate = 1, int prio = 0 );

		// Infinte run loop. Before the update function is
		// called, getShm() is called.  Then the update function
		// is called.  When the update exits, setShm is called.
		// since setShm is a virtual function, only the values
		// of interest to the specific thread are set. This
		// function does not need to be overwritten
		virtual void run(void);

		// get member info
		pthread_t getTid() const;
		pid_t getPid() const;
		String getName() const;

		// set loop running or not
		virtual void setRunning(bool run);
		virtual bool isRunning() { return (execRate >= 0 && running); }
		// shut down nicely
		virtual void shutdown(void);
		// close any open interfaces
		virtual void close(void);
		// display statistics
		virtual void displayStats();

		// Mutex locking functions. Do NOT overload this functions.
		void mutex_lock(void);
		void mutex_unlock(void);

	protected:
		// Update values, if a basic thread the only this
		// function needs to be overwritten.  If more
		// complicated then run function will need to be
		// overwritten.  If the run function isn't overloaded, then
		// this MUST be overloaded by the derived class.
		virtual void update();

		// set memory area, only what you need.  Since threads
		// are different, this function will almost always be overloaded.
		// The only time is when the running thread doesn't need access
		// to the shared memory area
		virtual void setShm();

		// copy the shared memory, usaually doesn't need
		// to be overwritten since the shmVar is simply updated
		// from the values in the table.  Thus, be careful using
		// the shmVar as the working variable. It is better to use
		// a working copy of the variables, that is copied to the actual
		// shared memory area in setShm.
		virtual void getShm();

		// This is the exit point of the thread. Use shutdown()
		// to externally stop a thread.  This function should 
		// perform the proper closing functions and actions, software
		// and hardware. 
		virtual void exit();

		// calculate run rates and times
		void setRunStat();

};

#endif // _PTHREAD_VC_H
